#include "thermostat.h"
#include <esp_matter.h>
#include <esp_matter_cluster.h>
#include <esp_matter_endpoint.h>
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <esp_matter_attribute.h>
#include <esp_matter_core.h>
#include <app/data-model/Decode.h> // Required for chip::DataModel::Decode
#include <app/CommandHandler.h>
#include <app/clusters/scenes-server/scenes-server.h>
#include <app-common/zap-generated/attributes/Accessors.h>

#include <app/util/attribute-storage.h>

using namespace chip;
using namespace chip::app::Clusters;
using namespace chip::app::Clusters::Thermostat;
using chip::Protocols::InteractionModel::Status;

// 静态成员初始化
const char *TAG = "THERMOSTAT";

// 温控器场景处理器类
class ThermostatSceneHandler : public scenes::DefaultSceneHandlerImpl
{
public:
    static constexpr uint8_t kThermostatScenableAttributesCount = 3;
    ThermostatSceneHandler() = default;

    // SceneHandler接口实现
    void GetSupportedClusters(chip::EndpointId endpoint, chip::Span<chip::ClusterId> &clusterBuffer) override;
    bool SupportsCluster(chip::EndpointId endpoint, chip::ClusterId cluster) override;

    CHIP_ERROR SerializeSave(chip::EndpointId endpoint, chip::ClusterId cluster, chip::MutableByteSpan &serializedBytes) override;

    CHIP_ERROR ApplyScene(chip::EndpointId endpoint, chip::ClusterId cluster, const chip::ByteSpan &serializedBytes,
                          chip::scenes::TransitionTimeMs timeMs) override;

    template <typename Type>
    void AddAttributeValuePair(ScenesManagement::Structs::AttributeValuePairStruct::Type *pairs, AttributeId id, Type value,
                               size_t &attributeCount);
};

ThermostatServer ThermostatServer::instance;
static ThermostatSceneHandler sThermostatSceneHandler;
chip::scenes::SceneHandler *ThermostatServer::GetSceneHandler()
{
    return &sThermostatSceneHandler;
}

bool ThermostatServer::HasFeature(chip::EndpointId endpoint, Feature feature)
{
    bool success;
    uint32_t featureMap;
    success = (chip::app::Clusters::Identify::Attributes::FeatureMap::Get(endpoint, &featureMap) == Status::Success);
    ESP_LOGI(TAG, "HasFeature: featureMap %lx, feature %ld", featureMap, to_underlying(feature));
    return success ? ((featureMap & to_underlying(feature))) : false;
}

void ThermostatServer::stop_temperature_simulation()
{
    if (temperature_task_handle != nullptr)
    {
        vTaskDelete(temperature_task_handle);
        temperature_task_handle = nullptr;
        ESP_LOGI(TAG, "Temperature simulation task stopped");
    }
}

void ThermostatServer::set_temperature(int16_t temperature)
{
    if (endpoint_id != 0)
    {
        esp_matter_attr_val_t val = esp_matter_int16(temperature);
        esp_matter::attribute::update(endpoint_id, Thermostat::Id,
                                      Thermostat::Attributes::LocalTemperature::Id, &val);
        ESP_LOGI(TAG, "Set local temperature to: %d.%02d°C",
                 temperature / 100, temperature % 100);
    }
}

int16_t ThermostatServer::get_current_temperature() const
{
    // 这里可以添加获取当前温度的逻辑
    // 目前返回一个默认值，实际实现可能需要从属性中读取
    return 2000; // 20.00°C
}

// 静态成员函数 - 温度模拟任务
void ThermostatServer::temperature_simulation_task(void *pvParameters)
{
    ThermostatServer *thermostat = static_cast<ThermostatServer *>(pvParameters);
    int16_t current_temperature = 2000; // 初始温度 20.00°C
    bool increasing = true;

    while (1)
    {
        // 更新温度值
        if (increasing)
        {
            current_temperature += 50; // 增加 0.5°C
            if (current_temperature >= 3000)
            { // 达到 30.00°C
                increasing = false;
            }
        }
        else
        {
            current_temperature -= 50; // 减少 0.5°C
            if (current_temperature <= 1500)
            { // 达到 15.00°C
                increasing = true;
            }
        }

        // 使用类的成员函数设置温度
        thermostat->set_temperature(current_temperature);

        // 每5秒更新一次
        vTaskDelay(pdMS_TO_TICKS(5000));
    }
}

esp_matter::endpoint_t *ThermostatServer::create_device(esp_matter::node_t *node)
{
    // 创建恒温器端点
    // 配置恒温器端点参数，包括本地温度、控制操作序列、系统模式、占用相关属性和设定点回退属性
    esp_matter::endpoint::thermostat::config_t thermostat_ep_config;
    thermostat_ep_config.thermostat.local_temperature = nullptr; // 使用默认值
    thermostat_ep_config.thermostat.control_sequence_of_operation = chip::to_underlying(Thermostat::ControlSequenceOfOperationEnum::kCoolingAndHeating);
    thermostat_ep_config.thermostat.system_mode = chip::to_underlying(Thermostat::SystemModeEnum::kOff);
    thermostat_ep_config.thermostat.occupancy.unoccupied_setback = 100;     // 1.00°C 回退
    thermostat_ep_config.thermostat.occupancy.unoccupied_setback_min = 100; // 1.00°C 最小回退
    thermostat_ep_config.thermostat.occupancy.unoccupied_setback_max = 200; // 2.00°C 最大回退
    thermostat_ep_config.thermostat.setback.occupied_setback = 200;         // 2.00°C 回退
    thermostat_ep_config.thermostat.setback.occupied_setback_min = 100;     // 1.00°C 最小回退
    thermostat_ep_config.thermostat.setback.occupied_setback_max = 200;     // 2.00°C 最大回退

    // 创建恒温器端点
    esp_matter::endpoint_t *thermostat_endpoint = esp_matter::endpoint::thermostat::create(
        node, &thermostat_ep_config, esp_matter::ENDPOINT_FLAG_NONE, this);

    if (!thermostat_endpoint)
    {
        ESP_LOGE(TAG, "Failed to create thermostat endpoint");
        return NULL;
    }

    endpoint_id = esp_matter::endpoint::get_id(thermostat_endpoint);
    ESP_LOGI(TAG, "Thermostat endpoint created with ID: %d", endpoint_id);

    // 从刚创建的端点中获取 "恒温器集群" (Thermostat Cluster) 的指针。
    // 集群是端点内部功能模块的集合，恒温器集群包含了所有与恒温器相关的属性和命令。
    thermostat_cluster = esp_matter::cluster::get(endpoint_id, Thermostat::Id);

    // 设置恒温器运行模式属性
    esp_matter::cluster::thermostat::attribute::create_thermostat_running_mode(thermostat_cluster, chip::to_underlying(Thermostat::ThermostatRunningModeEnum::kOff));

    // 设置温度限制属性
    esp_matter::cluster::thermostat::attribute::create_min_cool_setpoint_limit(thermostat_cluster, 1800); // 18.00°C
    esp_matter::cluster::thermostat::attribute::create_max_cool_setpoint_limit(thermostat_cluster, 3000); // 30.00°C
    esp_matter::cluster::thermostat::attribute::create_min_heat_setpoint_limit(thermostat_cluster, 1500); // 15.00°C
    esp_matter::cluster::thermostat::attribute::create_max_heat_setpoint_limit(thermostat_cluster, 3000); // 30.00°C

    // 添加功能特性
    esp_matter::cluster::thermostat::feature::occupancy::add(thermostat_cluster, &(thermostat_ep_config.thermostat.occupancy));
    esp_matter::cluster::thermostat::feature::setback::add(thermostat_cluster, &(thermostat_ep_config.thermostat.setback));

    // 添加恒温器用户界面配置集群
    esp_matter::cluster::thermostat_user_interface_configuration::config_t ui_config;
    esp_matter::cluster_t *ui_cluster = esp_matter::cluster::thermostat_user_interface_configuration::create(
        thermostat_endpoint, &ui_config, esp_matter::CLUSTER_FLAG_SERVER);

    // 手动添加场景管理集群
    esp_matter::cluster_t *scenes_mgmt_cluster = esp_matter::cluster::get(endpoint_id, ScenesManagement::Id);
    if (!scenes_mgmt_cluster)
    {
        scenes_mgmt_cluster = esp_matter::cluster::scenes_management::create(
            thermostat_endpoint, &thermostat_ep_config.scenes_management, esp_matter::CLUSTER_FLAG_SERVER);
        if (!scenes_mgmt_cluster)
        {
            ESP_LOGE(TAG, "Failed to create raw Scenes Management cluster");
            return NULL;
        }
        ESP_LOGI(TAG, "Scenes Management cluster created manually without default server.");
    }
    else
    {
        ESP_LOGI(TAG, "Scenes Management cluster found on endpoint");
    }

    // 注册场景处理器
    chip::app::Clusters::ScenesManagement::ScenesServer::Instance().RegisterSceneHandler(endpoint_id, ThermostatServer::Instance().GetSceneHandler());
    ESP_LOGI(TAG, "ThermostatSceneHandler registered for endpoint %d", endpoint_id);

    // 可选：创建温度模拟任务
    // xTaskCreate(temperature_simulation_task, "temp_sim", 4096, this, 5, &temperature_task_handle);

    return thermostat_endpoint;
}

void ThermostatServer::set_system_mode(uint8_t mode)
{
    if (endpoint_id != 0 && thermostat_cluster != nullptr)
    {
        esp_matter_attr_val_t val = esp_matter_uint8(mode);
        esp_matter::attribute::update(endpoint_id, Thermostat::Id,
                                      Thermostat::Attributes::SystemMode::Id, &val);
        ESP_LOGI(TAG, "Set System Mode to: %d", mode);
    }
    else
    {
        ESP_LOGE(TAG, "Failed to set System Mode: Endpoint or cluster not initialized");
    }
}

void ThermostatServer::set_heating_setpoint(int16_t setpoint)
{
    if (endpoint_id != 0 && thermostat_cluster != nullptr)
    {
        esp_matter_attr_val_t val = esp_matter_int16(setpoint);
        esp_matter::attribute::update(endpoint_id, Thermostat::Id,
                                      Thermostat::Attributes::OccupiedHeatingSetpoint::Id, &val);
        ESP_LOGI(TAG, "Set Heating Setpoint to: %d.%02d°C", setpoint / 100, setpoint % 100);
    }
    else
    {
        ESP_LOGE(TAG, "Failed to set Heating Setpoint: Endpoint or cluster not initialized");
    }
}

void ThermostatServer::set_cooling_setpoint(int16_t setpoint)
{
    if (endpoint_id != 0 && thermostat_cluster != nullptr)
    {
        esp_matter_attr_val_t val = esp_matter_int16(setpoint);
        esp_matter::attribute::update(endpoint_id, Thermostat::Id,
                                      Thermostat::Attributes::OccupiedCoolingSetpoint::Id, &val);
        ESP_LOGI(TAG, "Set Cooling Setpoint to: %d.%02d°C", setpoint / 100, setpoint % 100);
    }
    else
    {
        ESP_LOGE(TAG, "Failed to set Cooling Setpoint: Endpoint or cluster not initialized");
    }
}
uint16_t ThermostatServer::getEndpointIndex(chip::EndpointId endpoint)
{
    return emberAfGetClusterServerEndpointIndex(endpoint, Thermostat::Id, MATTER_DM_THERMOSTAT_CLUSTER_SERVER_ENDPOINT_COUNT);
}
// ============================================================================
// ThermostatSceneHandler 实现
// ============================================================================

void ThermostatSceneHandler::GetSupportedClusters(chip::EndpointId endpoint, chip::Span<chip::ClusterId> &clusterBuffer)
{
    ClusterId *buffer = clusterBuffer.data();
    if (emberAfContainsServer(endpoint, Thermostat::Id) && clusterBuffer.size() >= 1)
    {
        buffer[0] = Thermostat::Id;
        clusterBuffer.reduce_size(1);
    }
    else
    {
        clusterBuffer.reduce_size(0);
    }
    ESP_LOGI(TAG, "GetSupportedClusters called for endpoint %d, returning Thermostat cluster", endpoint);
}

bool ThermostatSceneHandler::SupportsCluster(chip::EndpointId endpoint, chip::ClusterId cluster)
{
    bool supported = (cluster == Thermostat::Id) && (emberAfContainsServer(endpoint, Thermostat::Id));
    ESP_LOGI(TAG, "SupportsCluster called for endpoint %d, cluster %lu, supported: %s",
             endpoint, static_cast<unsigned long>(cluster), supported ? "true" : "false");
    return supported;
}

CHIP_ERROR ThermostatSceneHandler::SerializeSave(chip::EndpointId endpoint, chip::ClusterId cluster, chip::MutableByteSpan &serializedBytes)
{

    ESP_LOGI(TAG, "SerializeSave: entry");
    using AttributeValuePair = ScenesManagement::Structs::AttributeValuePairStruct::Type;

    AttributeValuePair pairs[kThermostatScenableAttributesCount];

    size_t attributeCount = 0;

    if (ThermostatServer::Instance().HasFeature(endpoint, ThermostatServer::Feature::kHeating))
    {
        int16_t Value;
        if (Status::Success != Attributes::OccupiedHeatingSetpoint::Get(endpoint, &Value))
        {
            Value = ThermostatServer::Instance().kDefaultHeatingSetpoint;
        }
        ESP_LOGI(TAG, "SerializeSave: OccupiedHeatingSetpoint %d", Value);
        AddAttributeValuePair<int16_t>(pairs, Attributes::OccupiedHeatingSetpoint::Id, Value, attributeCount);
    }
    if (ThermostatServer::Instance().HasFeature(endpoint, ThermostatServer::Feature::kCooling))
    {
        int16_t Value;
        if (Status::Success != Attributes::OccupiedCoolingSetpoint::Get(endpoint, &Value))
        {
            Value = ThermostatServer::Instance().kDefaultCoolingSetpoint;
        }
        ESP_LOGI(TAG, "SerializeSave: OccupiedCoolingSetpoint %d", Value);
        AddAttributeValuePair<int16_t>(pairs, Attributes::OccupiedCoolingSetpoint::Id, Value, attributeCount);
    }

    app::DataModel::List<AttributeValuePair> attributeValueList(pairs, attributeCount);

    return EncodeAttributeValueList(attributeValueList, serializedBytes);
}

CHIP_ERROR ThermostatSceneHandler::ApplyScene(chip::EndpointId endpoint, chip::ClusterId cluster, const chip::ByteSpan &serializedBytes,
                                              chip::scenes::TransitionTimeMs timeMs)
{
    ESP_LOGI(TAG, "ApplyScene called for endpoint %d, cluster %lu, transition time %lu ms",
             endpoint, static_cast<unsigned long>(cluster), static_cast<unsigned long>(timeMs));

    app::DataModel::DecodableList<ScenesManagement::Structs::AttributeValuePairStruct::DecodableType> attributeValueList;

    ReturnErrorOnFailure(DecodeAttributeValueList(serializedBytes, attributeValueList));

    size_t attributeCount = 0;

    ReturnErrorOnFailure(attributeValueList.ComputeSize(&attributeCount));
    VerifyOrReturnError(attributeCount <= kThermostatScenableAttributesCount, CHIP_ERROR_BUFFER_TOO_SMALL);

    auto pair_iterator = attributeValueList.begin();
    while (pair_iterator.Next())
    {
        auto &decodePair = pair_iterator.GetValue();

        switch (decodePair.attributeID)
        {
        case Attributes::SystemMode::Id:
            ESP_LOGI(TAG, "ApplyScene: Attributes::SystemMode::Id");
            /* code */
            break;
        case Attributes::OccupiedCoolingSetpoint::Id:
            ESP_LOGI(TAG, "ApplyScene: Attributes::OccupiedCoolingSetpoint::Id");

            break;
        case Attributes::OccupiedHeatingSetpoint::Id:
            ESP_LOGI(TAG, "ApplyScene: Attributes::OccupiedHeatingSetpoint::Id");
            break;
        case Attributes::UnoccupiedCoolingSetpoint::Id:
            ESP_LOGI(TAG, "ApplyScene: Attributes::UnoccupiedCoolingSetpoint::Id");
            break;
        default:
            ESP_LOGI(TAG, "ApplyScene: decodePair.attributeID %ld", decodePair.attributeID);

            break;
        }
    }

    return CHIP_NO_ERROR;
}
template <typename Type>
void ThermostatSceneHandler::AddAttributeValuePair(ScenesManagement::Structs::AttributeValuePairStruct::Type *pairs, AttributeId id, Type value, size_t &attributeCount)
{
    static_assert((std::is_same_v<Type, uint8_t>) ||
                      (std::is_same_v<Type, uint16_t>) ||
                      (std::is_same_v<Type, int8_t>) ||
                      (std::is_same_v<Type, int16_t>),
                  "Type must be uint8_t or uint16_t");

    pairs[attributeCount].attributeID = id;
    if constexpr ((std::is_same_v<Type, uint8_t>))
    {
        pairs[attributeCount].valueUnsigned8.SetValue(value);
    }
    else if constexpr ((std::is_same_v<Type, uint16_t>))
    {
        pairs[attributeCount].valueUnsigned16.SetValue(value);
    }
    else if constexpr ((std::is_same_v<Type, int8_t>))
    {
        pairs[attributeCount].valueSigned8.SetValue(value);
    }
    else if constexpr ((std::is_same_v<Type, int16_t>))
    {
        pairs[attributeCount].valueSigned16.SetValue(value);
    }
    attributeCount++;
}
